package com.lemon.core.base.util;

import cn.hutool.core.collection.CollUtil;
import com.lemon.core.base.pojo.tree.SelectVO;
import com.lemon.core.base.pojo.tree.TreeNode;
import com.lemon.core.base.pojo.tree.TreeSelectVO;
import lombok.experimental.UtilityClass;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 树形节点工具类
 *
 * @author pan
 * @date 2018-09-02
 */
@UtilityClass
public class TreeUtils {

    /**
     * 使用递归方法生成下拉(TreeSelect)层级列表
     *
     * @param treeNodes 传入的树节点列表
     * @param root      根节点
     * @param <T>       树形结构
     * @return {@link SelectVO}
     */
    public <T extends TreeNode> List<SelectVO> buildSelectByRecursion(List<T> treeNodes, Object root) {
        List<SelectVO> trees = new ArrayList<>();
        Optional.ofNullable(treeNodes).orElse(new ArrayList<>()).stream()
                .filter(item -> Objects.equals(root, item.getParentId()))
                .forEach(item -> {
                    SelectVO selectVO = new SelectVO(item.getId(), item.getLabel());
                    List<SelectVO> children = buildSelectByRecursion(treeNodes, item.getId());
                    if (CollUtil.isNotEmpty(children)) {
                        selectVO.setChildren(children);
                    }
                    trees.add(selectVO);
                });
        return trees;
    }

    /**
     * 使用递归方法生成下拉(TreeSelect)层级列表
     *
     * @param treeNodes 传入的树节点列表
     * @param root      根节点
     * @param <T>       树形结构
     * @return {@link TreeSelectVO}
     */
    public <T extends TreeNode> List<TreeSelectVO> buildTreeSelectByRecursion(List<T> treeNodes, Object root) {
        List<TreeSelectVO> trees = new ArrayList<>();
        Optional.ofNullable(treeNodes).orElse(new ArrayList<>()).stream()
                .filter(item -> Objects.equals(root, item.getParentId()))
                .forEach(item -> {
                    TreeSelectVO treeSelectVO = new TreeSelectVO(item.getId(), item.getLabel());
                    List<TreeSelectVO> children = buildTreeSelectByRecursion(treeNodes, item.getId());
                    if (CollUtil.isNotEmpty(children)) {
                        treeSelectVO.setChildren(children);
                    }
                    trees.add(treeSelectVO);
                });
        return trees;
    }

    /**
     * 两层循环实现建树
     *
     * @param treeNodes 传入的树节点列表
     * @param root      根节点
     * @param <T>       树形结构
     * @return {@link T}
     */
    public <T extends TreeNode> List<T> build(List<T> treeNodes, Object root) {
        List<T> trees = new ArrayList<>();
        for (T treeNode : treeNodes) {
            if (Objects.equals(root, treeNode.getParentId())) {
                trees.add(treeNode);
            }
            for (T it : treeNodes) {
                if (Objects.equals(treeNode.getId(), it.getParentId())) {
                    if (treeNode.getChildren() == null) {
                        treeNode.setChildren(new ArrayList<>());
                    }
                    treeNode.add(it);
                }
            }
        }
        return trees;
    }

    /**
     * 使用递归方法建树
     *
     * @param treeNodes 传入的树节点列表
     * @param root      根节点
     * @param <T>       树形结构
     * @return {@link T}
     */
    public <T extends TreeNode> List<T> buildByRecursive(List<T> treeNodes, Object root) {
        List<T> trees = new ArrayList<>();
        for (T treeNode : treeNodes) {
            if (root.equals(treeNode.getParentId())) {
                trees.add(findChildren(treeNode, treeNodes));
            }
        }
        return trees;
    }

    /**
     * 递归查找子节点
     *
     * @param treeNode  节点
     * @param treeNodes 传入的树节点列表
     * @param <T>       树形结构
     * @return {@link T}
     */
    public <T extends TreeNode> T findChildren(T treeNode, List<T> treeNodes) {
        for (T it : treeNodes) {
            if (Objects.equals(treeNode.getId(), it.getParentId())) {
                if (treeNode.getChildren() == null) {
                    treeNode.setChildren(new ArrayList<>());
                }
                treeNode.add(findChildren(it, treeNodes));
            }
        }
        return treeNode;
    }

}
